﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="LogicElementsFactory.cs" company="pwasiewicz">
//   pwasiewicz
// </copyright>
// <summary>
//   Defines the LogicElementsFactory type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace LogicSystem
{
    using System.Collections.Generic;
    using System.Linq;

    using LogicSystem.LogicGates;
    using LogicSystem.Wires;

    /// <summary>The logic elements factory.</summary>
    public class LogicElementsFactory
    {
        /// <summary>The simulating environment.</summary>
        private readonly SimulatingEnvironment simulatingEnvironment;

        /// <summary>Initializes a new instance of the <see cref="LogicElementsFactory"/> class.</summary>
        public LogicElementsFactory()
        {
            this.simulatingEnvironment = new SimulatingEnvironment();
        }

        /// <summary>
        /// Creates the logic system simulator.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputWires">The input wires.</param>
        /// <returns>Logic system simulator.</returns>
        public LogicSystemSimulator CreateLogicSystemSimulator(Wire outputWire, IEnumerable<Wire> inputWires)
        {
            return this.CreateLogicSystemSimulator(outputWire, inputWires.ToArray());
        }

        /// <summary>
        /// Creates the logic system simulator.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputWires">The input wires.</param>
        /// <returns>Logic system simulator.</returns>
        public LogicSystemSimulator CreateLogicSystemSimulator(Wire outputWire, params Wire[] inputWires)
        {
            var lss = this.CreateLogicSystemSimulator();
            lss.AddInputWires(inputWires);
            lss.OutputWire = outputWire;

            return lss;
        }

        /// <summary>The create logic system simulator.</summary>
        /// <returns>The <see cref="LogicSystemSimulator"/>.</returns>
        public LogicSystemSimulator CreateLogicSystemSimulator()
        {
            return new LogicSystemSimulator { SimulatingEnvironment = this.simulatingEnvironment };
        }

        /// <summary>
        /// Creates the wire.
        /// </summary>
        /// <returns>Wire reference.</returns>
        public Wire CreateWire()
        {
            return new Wire { SimulatingEnvironment = this.simulatingEnvironment };
        }

        /// <summary>
        /// Creates the AND gate.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputWires">The input wires.</param>
        /// <returns>Logic gate</returns>
        public LogicGate CreateGateAnd(Wire outputWire, IEnumerable<Wire> inputWires)
        {
            return this.CreateGateAnd(outputWire, inputWires.ToArray());
        }

        /// <summary>
        /// Creates the AND gate.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputWires">The input wires.</param>
        /// <returns>Logic gate</returns>
        public LogicGate CreateGateAnd(Wire outputWire, params Wire[] inputWires)
        {
            var gate = this.CreateGateAnd();
            gate.AddInputWires(inputWires);
            gate.OutputWire = outputWire;

            return gate;
        }

        /// <summary>
        /// Creates the gate and.
        /// </summary>
        /// <returns>The logic gate reference.</returns>
        public LogicGate CreateGateAnd()
        {
            return new GateAnd { SimulatingEnvironment = this.simulatingEnvironment };
        }

        /// <summary>
        /// Creates the OR gate.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputWires">The input wires.</param>
        /// <returns>Logic gate</returns>
        public LogicGate CreateGateOr(Wire outputWire, IEnumerable<Wire> inputWires)
        {
            return this.CreateGateOr(outputWire, inputWires.ToArray());
        }

        /// <summary>
        /// Creates the OR gate.
        /// </summary>
        /// <param name="outputWire">The output wire.</param>
        /// <param name="inputBaseWires">The input wires.</param>
        /// <returns>Logic gate</returns>
        public LogicGate CreateGateOr(Wire outputWire, params Wire[] inputWires)
        {
            var gate = this.CreateGateOr();
            gate.AddInputWires(inputWires);
            gate.OutputWire = outputWire;

            return gate;
        }

        /// <summary>
        /// Creates the gate or.
        /// </summary>
        /// <returns>The logic gate reference.</returns>
        public LogicGate CreateGateOr()
        {
            return new GateOr { SimulatingEnvironment = this.simulatingEnvironment };
        }
    }
}
